package junit;

import base.AST;
import base.Identifier;
import base.Interpreter;
import expressions.*;
import instructions.*;
import values.Integer;

public class Fibo {

	public static void main(String args[]) {
		
		int mainArgument = 10;
		
		/*
		 * 
		 * def fibo(n) { print(0); print(1); subFibo(0, 1, n-2); }
		 * 
		 * def subFibo(ii, i, n) { local (newI) { newI = ii + i; print(newI); if
		 * (n-1 > 0) { subFibo(i, newI, n-1); } } }
		 * 
		 * fibo(5);
		 */


		
		///////////////////////////////////////////
		
		// SubFibo :
		
		Identifier ii = new Identifier("ii");
		Identifier i = new Identifier("i");
		Identifier newI = new Identifier("newI");
		Identifier n = new Identifier("n");
		
		Add addition = new Add(new VariableAccess(ii), new VariableAccess(i));
		VariableAssign assNewI = new VariableAssign(newI, addition);
		Composition addAndPrint = new Composition(assNewI, new Print(new VariableAccess(newI)));
		
		Substract testSubstract = new Substract(new VariableAccess(n), new Integer(1));
		Greater test = new Greater(testSubstract, new Integer(0));
		
		Identifier[] argsSubSubFiboCall = { null, null, null };
		AST[] argsSubSubFiboCallValues = {
				new VariableAccess(i),
				new VariableAccess(newI),
				new Substract(new VariableAccess(n),
						new Integer(1)) };
		FunctionCall subSubFiboCall = new FunctionCall(new Identifier("subFibo"),
				argsSubSubFiboCall, argsSubSubFiboCallValues);
		
		If ifPart = new If(test, subSubFiboCall, null);
		
		Composition localBody = new Composition(addAndPrint, ifPart);
		
		Local subFiboBody = new Local(newI, localBody);
		
		Identifier argsSubFibo[] = { new Identifier("ii"),  new Identifier("i"),  new Identifier("n") };
		FunctionDef subFibo = new FunctionDef(new Identifier("subFibo"), subFiboBody, argsSubFibo);
		
		///////////////////////////////////////////
		
		// Fibo :

		Composition prints = new Composition(new Print(new Integer(0)),
				new Print(new Integer(1)));

		Identifier[] argsSubFiboCall = { null, null, null };
		AST[] argsSubFiboCallValues = {
				new Integer(0),
				new Integer(1),
				new Substract(new VariableAccess(new Identifier("n")),
						new Integer(2)) };
		FunctionCall subFiboCall = new FunctionCall(new Identifier("subFibo"),
				argsSubFiboCall, argsSubFiboCallValues);

		Composition fiboBody = new Composition(prints, subFiboCall);

		Identifier argsFibo[] = { new Identifier("n") };
		FunctionDef fibo = new FunctionDef(new Identifier("fibo"), fiboBody, argsFibo);
		
		///////////////////////////////////////////
		
		// Call + Glue :

		Identifier[] argsFiboCall = { null };
		AST[] argsFiboCallValues = {
				new Integer(mainArgument) };
		
		FunctionCall fiboCall = new FunctionCall(new Identifier("fibo"),
				argsFiboCall, argsFiboCallValues);
		
		Composition twoFunctions = new Composition(subFibo, fibo);
		
		Composition finalCode = new Composition(twoFunctions, fiboCall) ;
		
		Interpreter.instr(finalCode);
		
	}

}
